package com.forum.module.blog.service.article;

import com.alibaba.nacos.shaded.com.google.common.annotations.VisibleForTesting;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.forum.framework.common.exception.util.ServiceExceptionUtils;
import com.forum.framework.common.pojo.PageResult;
import com.forum.framework.common.util.object.BeanUtils;
import com.forum.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.forum.framework.security.core.util.SecurityUtils;
import com.forum.module.blog.controller.article.vo.ArticlePageReqVO;
import com.forum.module.blog.controller.article.vo.ArticleSaveReqVO;
import com.forum.module.blog.dal.dataobject.article.ArticleDO;
import com.forum.module.blog.dal.dataobject.comment.CommentDO;
import com.forum.module.blog.dal.dataobject.likes.LikesDO;
import com.forum.module.blog.dal.mysql.article.ArticleMapper;
import com.forum.module.blog.dal.mysql.comment.CommentMapper;
import com.forum.module.blog.dal.mysql.likes.LikesMapper;
import org.springframework.stereotype.Service;

import java.util.Objects;

import static com.forum.module.system.enums.ErrorCodeConstants.ARTICLE_NOT_EXISTS;

/**
 * 功能:
 * 作者:ouyzh
 * 日期:2025/3/2 18:23
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, ArticleDO> implements ArticleService {
    private final ArticleMapper articleMapper;

    private final LikesMapper likesMapper;

    private final CommentMapper commentMapper;

    public ArticleServiceImpl(ArticleMapper articleMapper,
                              LikesMapper likesMapper,
                              CommentMapper commentMapper) {
        this.articleMapper = articleMapper;
        this.likesMapper = likesMapper;
        this.commentMapper = commentMapper;
    }

    @Override
    public Long createArticle(ArticleSaveReqVO reqVO) {
        Long loginUserId = SecurityUtils.getLoginUserId();
        ArticleDO articleDO = BeanUtils.toBean(reqVO, ArticleDO.class);
        articleDO.setViews(0L);
        articleDO.setLikes(0L);
        articleDO.setComments(0L);
        articleDO.setUserId(loginUserId);
        articleDO.setStatus(reqVO.getStatus() != null ? reqVO.getStatus() : 1);
        articleMapper.insert(articleDO);

        return articleDO.getId();
    }

    @Override
    public void updateArticle(ArticleSaveReqVO reqVO) {
        ArticleDO updateObj = BeanUtils.toBean(reqVO, ArticleDO.class);
        articleMapper.updateById(updateObj);
    }

    @Override
    public void deleteById(Long id) {
        // 1. 校验文章存在
        validateArticleExists(id);

        // 2.1 删除用户
        articleMapper.deleteById(id);
    }

    @Override
    public PageResult<ArticleDO> getArticlePage(ArticlePageReqVO pageReqVO) {
        PageResult<ArticleDO> articleDOPageResult = articleMapper.selectPage(pageReqVO);
        return Objects.requireNonNullElseGet(articleDOPageResult, PageResult::empty);
    }

    @Override
    public ArticleDO getArticle(Long id) {
        ArticleDO articleDO = articleMapper.selectById(id);

        articleMapper.update(null, new LambdaUpdateWrapper<ArticleDO>()
                .eq(ArticleDO::getId, articleDO.getId())
                .eq(ArticleDO::getStatus, 1)
                .setSql("views = views + 1"));

        Long likes = likesMapper.selectCount(new LambdaQueryWrapperX<LikesDO>()
                .eqIfPresent(LikesDO::getArticleId, articleDO.getId()));

        Long comments = commentMapper.selectCount(new LambdaQueryWrapperX<CommentDO>()
                .eqIfPresent(CommentDO::getArticleId, articleDO.getId()));

        articleDO.setLikes(likes);
        articleDO.setComments(comments);

        return articleDO;
    }

    @VisibleForTesting
    ArticleDO validateArticleExists(Long id) {
        if (id == null) {
            return null;
        }
        ArticleDO articleDO = articleMapper.selectById(id);
        if (articleDO == null) {
            throw ServiceExceptionUtils.exception(ARTICLE_NOT_EXISTS);
        }
        return articleDO;
    }
}
